package com.eclipse.e20200201_多线程同步.同步锁_实例锁;

public class SyncTest implements Runnable{
    //共享资源变量
    int count = 0;

    @Override
    public synchronized void run() {
        for (int i = 0; i < 5; i++) {
//            increaseCount();
            System.out.println(Thread.currentThread().getName()+":"+count++);
        }
    }


	public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest1 = new SyncTest();
//        SyncTest syncTest2 = new SyncTest();
        Thread thread1 = new Thread(syncTest1,"thread1");
        Thread thread2 = new Thread(syncTest1, "thread2");//new两个实例的话。这就意味存在了两个不同的实例锁，就保证不了线程安全，需要变成类锁
        thread1.start();
        thread2.start();
    }
}
/*
 * Synchronized三种用法
 * 首先我们了解到Java中的线程同步锁可以是任意对象。
这里我们介绍synchronized的三种应用方式：

1.作用于实例方法，当前实例加锁，进入同步代码前要获得当前实例的锁；

2.作用于静态方法，当前类加锁，进去同步代码前要获得当前类对象的锁；

3.作用于代码块，这需要指定加锁的对象，对所给的指定对象加锁，进入同步代码前要获得指定对象的锁。

这三种应用方式接下来分别介绍

synchronized修饰实例方法（普通方法）

  使用时，作用范围为整个函数，这里所谓的实例锁就是调用该实例方法（不包括静态方法）的对象。不多BB，上代码：
【demo1】

作者：c_ychao
链接：https://www.jianshu.com/p/27f5935cafd8
来源：简书

著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
代码中开启了两个线程去操作一个变量（共享变量）,count++是先读取值，再写回一个新值。我们想一下，如果第一个线程执行这一过程中，第二个线程拿到写回之前的count值，
做count++操作，那么这就造成了线程不安全。所以这里在run方法加上synchronized，获取一个对象锁，代码中的实例锁就是syncTest1了。
  同时我们从输出结果看出：当一个线程正在访问一个对象synchronized实例方法时，别的线程是访问不了的。一个对象一把锁说的就是这个，当线程获取了该对象的锁后，其他线程无法获取该对象的锁，
当然就访问不了该对象的synchronized方法，但是！但是！但是！可以访问该对象的其他未被synchronized修饰的方法。
  如果是一个线程 A 需要访问实例对象 obj1 的 synchronized 方法 f1(当前对象锁是obj1)，另一个线程 B 需要访问实例对象 obj2 的 synchronized 方法 f2(当前对象锁是obj2)，
这样是允许的，因为两个实例对象锁并不同相同，此时如果两个线程操作数据并非共享的，线程安全是有保障的，遗憾的是如果两个线程操作的是共享数据，那么线程安全就有可能无法保证了。
我们把上面代码中的main方法中的注释放开，表达这一线程不安全的现象
【demo2】
我们从输出结果来看，两个线程可能同时拿到共享变量去做count++操作。上述操作中虽然我们的run方法还是使用synchronized修饰，但是我们new了两个实例。
这就意味存在了两个不同的实例锁，thread1和thread2分别进入了syncTest1和syncTest2的实例锁，当然保证不了线程安全。但是我们也有解决方案啦：如果synchronized修饰的是静态方法呢？下面我们再介绍修饰静态方法。


 */